home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / sounds / tools / soundzap-2.0.lha / SoundZAP.c < prev    next >
C/C++ Source or Header  |  1992-03-29  |  11KB  |  424 lines

  1. /************************/
  2. /**SoundZAP Version 2.0**/
  3. /************************/
  4.  
  5. /*
  6.  *  This program was compiled with Matthew Dillon's DICE C compiler, which
  7.  *  automatically opens and closes the Amiga libraries as they are needed.
  8.  *  If your compiler does not do this you will have to Add the appropriate
  9.  *  code (or get DICE!!).
  10.  */
  11.  
  12.  
  13. #include <exec/types.h>
  14. #include <exec/memory.h>
  15. #include <libraries/dos.h>
  16. #include <stdio.h>
  17. #include <iff/iff.h>
  18. #include <iff/8svx.h>
  19. #include "SoundZAP.h"
  20.  
  21.  
  22. void main(int argc, char *argv[])
  23. {
  24.     char comline[33];
  25.     struct options *Opt;
  26.  
  27.  
  28.     if (argc<2) GiveUsage;
  29.  
  30.     if ((Opt=(UBYTE *)AllocMem(sizeof(struct options),MEMF_PUBLIC))==NULL)
  31.         CleanUp(Opt,5);
  32.  
  33.     Opt->BuffSize  = DEFAULT_SIZE;
  34.     Opt->FlipSign  = FALSE;
  35.     Opt->KillChunk = FALSE;
  36.     Opt->SampRate  = DEFAULT_RATE;
  37.     Opt->IFFOut    = TRUE;
  38.     Opt->InType    = UNKNOWN;
  39.     Opt->MuLaw     = FALSE;
  40.     Opt->SampChk   = TRUE;
  41.     Opt->Size      = 0;
  42.  
  43.     while (--argc > 0)
  44.     {
  45.         strcpy(comline,argv[argc]);
  46.         if (comline[0]=='-')
  47.             ProcessOpt(Opt,comline);
  48.         else
  49.         {
  50.            strcpy(Opt->outname,Opt->inname);
  51.            strcpy(Opt->inname,comline);
  52.         }
  53.     }
  54.     if (strlen(Opt->inname)==0)
  55.         GiveUsage();
  56.  
  57.     if (strlen(Opt->outname)==0)
  58.     {
  59.         int l;
  60.  
  61.         strcpy(Opt->outname,Opt->inname);
  62.         l=strlen(Opt->outname);
  63.         if(Opt->outname[l-4]=='.')
  64.             Opt->outname[l-4]='\0';
  65.         if(Opt->outname[l-3]=='.')
  66.             Opt->outname[l-3]='\0';
  67.         strcat(Opt->outname,".iff");
  68.     }
  69.     printf("Input File: %s\nOutput File: %s\n",Opt->inname,Opt->outname);
  70.     printf("Buffer Size: %d bytes\n",Opt->BuffSize);
  71.     if(!Opt->SampChk)
  72.         printf("Sample Rate: %d samples per second\n",Opt->SampRate);
  73.     AnalyzeData(Opt);
  74.     CleanUp(Opt,0);
  75. }
  76.  
  77.  
  78. void GiveUsage()
  79. {
  80.     printf("Usage:  SoundZAP [<options>] SOURCE [DESTINATION]\n");
  81.     printf("    (actually, the options can appear anywhere)\n\n");
  82.     printf("    options:    -w         Output RAW Opt->Data\n");
  83.     printf("                -s         Toggle signed/unsigned output\n");
  84.     printf("                -n         Don't create extra chunks in IFF output\n");
  85.     printf("                -f         Assume input Opt->Data is RAW\n");
  86.     printf("                -b<n>      Use a buffer size of n kilobytes\n");
  87.     printf("                -r<n>      Change sample rate.\n");
  88.     printf("                            where n is the sample rate or\n");
  89.     printf("                            one of the built in values.\n");
  90.     printf("\n\nSee documentation for more info.\n");
  91.     printf("mrc113@psuvm.psu.edu\n");
  92.     exit(0);
  93. }
  94.  
  95. void ProcessOpt(struct options *Opt, char com[])
  96. {
  97.     int len;
  98.     ULONG n;
  99.  
  100.     switch (com[1])
  101.     {
  102.         case 'w' :  Opt->IFFOut=FALSE;
  103.                     break;
  104.  
  105.         case 's' :  Opt->FlipSign=TRUE;
  106.                     break;
  107.  
  108.         case 'n' :  Opt->KillChunk=TRUE;
  109.                     break;
  110.  
  111.         case 'f' :  Opt->InType=RAW;
  112.                     break;
  113.  
  114.         case 'b' :  len=strlen(com)-2;
  115.                     if (len==0)
  116.                         CleanUp(Opt,2);
  117.                     n=(ULONG)atoi(com+2)*1024;
  118.                     if (n!=0) Opt->BuffSize=n;
  119.                     break;
  120.  
  121.         case 'r' :  len=strlen(com)-2;
  122.                     if (len==0)
  123.                         CleanUp(Opt,3);
  124.                     if (len==1)
  125.                     {
  126.                         switch (com[2])
  127.                         {
  128.                             case '5' :  Opt->SampRate=5696;
  129.                                         break;
  130.  
  131.                             case '7' :  Opt->SampRate=7596;
  132.                                         break;
  133.  
  134.                             case '8' :  Opt->SampRate=8000;
  135.                                         break;
  136.  
  137.                             case '2' :  Opt->SampRate=22790;
  138.                                         break;
  139.  
  140.                             default  :  Opt->SampRate=11395;
  141.                         }
  142.                     }
  143.                     else
  144.                     {
  145.                         n=(LONG)atoi(com+2);
  146.                         if (n!=0) Opt->SampRate=n;
  147.                         else Opt->SampRate=11395;
  148.                     }
  149.                     Opt->SampChk=FALSE;
  150.                     break;
  151.  
  152.  
  153.         default  :  CleanUp(Opt,4);
  154.     }
  155. }
  156.  
  157. void CleanUp(struct options *Opt, int Error)
  158. {
  159.     if (Opt->Data) FreeMem(Opt->Data,Opt->BuffSize);
  160.     if (Opt) FreeMem(Opt,sizeof(struct options));
  161.     if (in)   Close(in);
  162.     if (out)  Close(out);
  163.     if (Error==0) exit(0);
  164.     else
  165.     {
  166.         printf("%s",ErrorMessages[Error]);
  167.         exit(20);
  168.     }
  169. }
  170.  
  171. void AnalyzeData(struct options *Opt)
  172. {
  173.     if ((Opt->Data=(UBYTE *)AllocMem(Opt->BuffSize,MEMF_PUBLIC))==NULL)
  174.         CleanUp(Opt,5);
  175.  
  176.     if ((in=(struct FileHandle *)Open(Opt->inname,MODE_OLDFILE))==NULL)
  177.         CleanUp(Opt,6);
  178.  
  179.     Read(in,Opt->Data,20);
  180.     if (Opt->InType==UNKNOWN)
  181.     {
  182.         if (!strncmp(Opt->Data,".snd",4))
  183.             ConvertAU(Opt);
  184.         else if (!strncmp(Opt->Data,"FORM",4))
  185.             /*ConvertIFF(Opt);*/ CleanUp(Opt,0);
  186.         else if (!strncmp(Opt->Data,"Creative Voice File",19))
  187.             ConvertVOC(Opt);
  188.     }
  189.     GuidoCheck(Opt);
  190. }
  191.  
  192. /*  This routine is a modified version of Guido van Rossum's (guido@cwi.nl)
  193.  *  'whatsound' routine. It guesses the sound file type (signed/unsigned/mu-law)
  194.  *  by checking how the values in the file are distributed. Thanks Guido!!
  195.  */
  196.  
  197. void GuidoCheck(struct options *Opt)
  198. {
  199.     LONG a,n,sum;
  200.     unsigned long bin[4];
  201.     int x;
  202.     BPTR op=Output();
  203.  
  204.     if(Opt->FlipSign)
  205.     {
  206.         Seek(in,0,OFFSET_END);
  207.         Opt->Size=Seek(in,0,OFFSET_BEGINNING);
  208.         ConvertRaw(Opt);
  209.     }
  210.  
  211.     Write(op,"Analyzing Data...",18);
  212.     for (a=0; a<4; a++)
  213.         bin[a]=0;
  214.     do
  215.     {
  216.         n=Read(in,Opt->Data,Opt->BuffSize);
  217.         for(a=0; a<n; a++)
  218.             bin[Opt->Data[a]/64]++;
  219.     }
  220.     while (n==Opt->BuffSize);
  221.     if(bin[2]==0 && bin[3]==0)
  222.         CleanUp(Opt,7);
  223.  
  224.     x=((bin[0]+bin[3])*100)/(bin[1]+bin[2]);
  225.     if(x>=300)
  226.         Opt->FlipSign=FALSE;
  227.     else if ( x <= 33)
  228.         Opt->FlipSign=TRUE;
  229.     else if ( (x >= 50) && (x <= 200))
  230.         Opt->MuLaw=TRUE;
  231.     printf("Done.\n");
  232.     if(Opt->SampChk && Opt->MuLaw) Opt->SampRate=8000;
  233.     Seek(in,0,OFFSET_END);
  234.     Opt->Size=Seek(in,0,OFFSET_BEGINNING);
  235.     ConvertRaw(Opt);
  236. }
  237.  
  238.  
  239. void ConvertRaw(struct options *Opt)
  240. {
  241.     LONG b_read,i;
  242.     int max;
  243.     signed char logs[256];
  244.     BPTR op=Output();
  245.  
  246.  
  247.     if((out=(struct FileHandle *)Open(Opt->outname,MODE_NEWFILE))==NULL)
  248.         CleanUp(Opt,8);
  249.  
  250.     if (Opt->IFFOut)
  251.         WriteIFFStuff(Opt);
  252.  
  253.     if (Opt->MuLaw)
  254.     {
  255.         Write(op,"Building log tables...",22);
  256.         max=getscale(Opt);
  257.         maketable(logs,max);
  258.         printf("Done.\n");
  259.         if (Opt->InType==AU)
  260.             Seek(in,32,OFFSET_BEGINNING);
  261.         else
  262.             Seek(in,0,OFFSET_BEGINNING);
  263.     }
  264.     Write(op,"Converting...",13);
  265.     do
  266.     {
  267.         b_read=Read(in,Opt->Data,Opt->BuffSize);
  268.         if(Opt->FlipSign)
  269.             for (i=0; i<b_read; i++)
  270.                 Opt->Data[i] ^= 0x80;
  271.         else if(Opt->MuLaw)
  272.             for (i=0; i<b_read; i++)
  273.                 Opt->Data[i]=logs[Opt->Data[i]];
  274.         Write(out,Opt->Data,b_read);
  275.     }
  276.     while(b_read==Opt->BuffSize);
  277.  
  278.     if(Opt->IFFOut)
  279.         Write(out,"\0\0\0",(4-Opt->Size%4)&3);
  280.     printf("Done.\n");
  281.     CleanUp(Opt,0);
  282. }
  283.  
  284. void WriteIFFStuff(struct options *Opt)
  285. {
  286.     int i,s;
  287.     ChunkHeader Form, V8Hdr, Body, Auth, Anno;
  288.  
  289.     Voice8Header V8H = {0,0,32,8363,1,0,Unity};
  290.  
  291.     if (Opt->KillChunk)
  292.         s=0;
  293.     else s=68;
  294.  
  295.     Form.ckID = FORM;
  296.     Form.ckSize = 40 + s + Opt->Size + ((4-(Opt->Size%4))&3);
  297.  
  298.     Write(out,&Form,8);
  299.  
  300.     i=ID_8SVX;
  301.     Write(out,&i,4);
  302.  
  303.     if (!Opt->KillChunk)
  304.     {
  305.         Auth.ckID  = ID_AUTH;
  306.         Auth.ckSize = 16;
  307.         Write(out,&Auth,8);
  308.         Write(out,Author,16);
  309.  
  310.         Anno.ckID = ID_ANNO;
  311.         Anno.ckSize = 36;
  312.         Write(out,&Anno,8);
  313.         Write(out,Annotation,36);
  314.     }
  315.  
  316.     V8Hdr.ckID = ID_VHDR;
  317.     V8Hdr.ckSize = 20;
  318.     Write(out,&V8Hdr,8);
  319.  
  320.     V8H.oneShotHiSamples = Opt->Size;
  321.     V8H.samplesPerSec = Opt->SampRate;
  322.     Write(out,&V8H,20);
  323.  
  324.     Body.ckID = ID_BODY;
  325.     Body.ckSize = Opt->Size + ((4-(Opt->Size%4))&3);
  326.     Write(out,&Body,8);
  327. }
  328.  
  329.  
  330. void ConvertVOC(struct options *Opt)
  331. {
  332.     UBYTE c[2];
  333.  
  334.  
  335.     if(Opt->SampChk)
  336.     {
  337.         Seek(in,30,OFFSET_BEGINNING);
  338.         Read(in,c,2);
  339.         if(c[1]!=0)
  340.             CleanUp(Opt,9);
  341.         Opt->SampRate=1000000/(256-c[0]);
  342.     }
  343.     Opt->FlipSign=TRUE;
  344.     Seek(in,0,OFFSET_END);
  345.     Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
  346.     Seek(in,32,OFFSET_BEGINNING);
  347.     ConvertRaw(Opt);
  348. }
  349.  
  350. void ConvertAU(struct options *Opt)
  351. {
  352.     ULONG i;
  353.     int q;
  354.  
  355.     Opt->MuLaw=TRUE;
  356.     Opt->InType=AU;
  357.     Seek(in,15,OFFSET_BEGINNING);
  358.     Read(in,&q,1);
  359.     if (q!=1) CleanUp(Opt,9);
  360.     Seek(in,0,OFFSET_END);
  361.     Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
  362.     if (Opt->SampChk)
  363.     {
  364.         Seek(in,18,OFFSET_BEGINNING);
  365.         Read(in,&Opt->SampRate,2);
  366.     }
  367.     ConvertRaw(Opt);
  368. }
  369.  
  370.  
  371. /*--------------------------------------------------------------------------*
  372.  * The following routine was extracted from posting by Brian Foley.         *
  373.  * Brian Foley          email: bfoley@greatlakes.Central.Sun.COM            *
  374.  * Systems Engineer     smail:  1000 Town Center                            *
  375.  * Sun Microsystems             Suite 1700                                  *
  376.  * GreatLakes Region            Southfield, MI 48075   (313) 352-7070       *
  377.  *--------------------------------------------------------------------------*/
  378.  
  379. int ulaw2linear(unsigned char ulawbyte)
  380. {
  381.         static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
  382.                int sign, exponent, mantissa, sample;
  383.  
  384.         ulawbyte    = ~ulawbyte;
  385.         sign        =  ulawbyte & 0x80;
  386.         exponent    = (ulawbyte >> 4) & 0x07;
  387.         mantissa    =  ulawbyte & 0x0F;
  388.         sample      = (exp_lut[exponent] + (mantissa << (exponent + 3)));
  389.         if ( sign ) sample = -sample;
  390.         return sample;
  391. }
  392. int getscale(struct options *Opt)
  393. {
  394.         int count, max = 0, i;
  395.  
  396.         do
  397.         {
  398.             count    = Read(in, Opt->Data, Opt->BuffSize);
  399.             for ( i = 0; i < count; i++ )
  400.                 max     = MAX(abs(ulaw2linear(Opt->Data[i])), max);
  401.         }
  402.         while ( count == Opt->BuffSize );
  403.  
  404.         return max;
  405. }
  406.  
  407. void maketable(signed char *logs, int max)
  408. {
  409.         int i, c, d;
  410.  
  411.         for ( i = 0; i < 256; i++ )
  412.         {
  413.                 c = ( ulaw2linear(i) * ulaw2linear(0) ) / max;
  414.                 d = abs(c) & 0xFF;
  415.                 if ( d > 0x7F )
  416.                     if ( c > 0 )
  417.                         logs[i] = (signed char) ( c / 256 + 1 );
  418.                     else
  419.                         logs[i] = (signed char) ( c / 256 - 1 );
  420.                 else
  421.                     logs[i] = (signed char) ( c / 256 );
  422.         }
  423. }
  424.